﻿using AutomaticScrewLocking.app;
using AutomaticScrewLocking.domain.autoTest.model.aggregates;
using AutomaticScrewLocking.domain.autoTest.service;
using AutomaticScrewLocking.domain.autoTest.service.impl;
using AutomaticScrewLocking.domain.localLog.service;
using AutomaticScrewLocking.domain.localLog.service.impl;
using AutomaticScrewLocking.domain.modbus.comm.model.entity;
using AutomaticScrewLocking.domain.modbus.comm.service;
using AutomaticScrewLocking.domain.modbus.comm.service.impl;
using AutomaticScrewLocking.domain.torque.dataStorage.model.valobj;
using AutomaticScrewLocking.domain.torque.dataStorage.service;
using AutomaticScrewLocking.types;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace AutomaticScrewLocking
{
    public partial class MainForm : Form
    {
        public string errorMsg;

        private PlcCommunicationService plcCommunicationService;

        private PlcParam plcParam;

        private SerialPort serialPort;

        private LogService logService;

        private DataStorageFactory factory;

        private AutoTestService autoTestService;

        // PLC连接状态
        private bool plcState = false;
        // 螺丝机连接状态
        private bool equipmentState = false;

        public MainForm()
        {
            InitializeComponent();
            serialPort = new SerialPort();
            logService = new LogServiceImpl();

            GlobalDelegate.updateUiLogDelegate = updateUiLog;
            GlobalDelegate.updateDataDelegate = updateData;

            logService.WriteLog("参数开始加载！");
            if (GlobalParam.getInstance().loadParam(out errorMsg) == false)
            {
                logService.WriteLog(errorMsg);  
            }
            else
            {
                logService.WriteLog("参数已经成功加载！");
            }

            plcParam = new PlcParam(GlobalParam.getInstance().param.plcIp, GlobalParam.getInstance().param.plcPort);
            plcCommunicationService = new PlcCommunicationServiceImpl(plcParam);
            factory = new DataStorageFactory();

            AutoTestParam autoTestParam = new AutoTestParam();
            autoTestParam.serialPort = this.serialPort;
            autoTestParam.PlcCommunicationService = this.plcCommunicationService;
            autoTestService = new AutoTestServiceImpl(autoTestParam);
        }

        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (GlobalParam.getInstance().saveParam(out errorMsg) == false)
            {
                MessageBox.Show(errorMsg);
            }
        }

        private void settingMenuItem_Click(object sender, EventArgs e)
        {
            // 使用using自动释放掉窗体
            using (ParamSetForm paramSetForm = new ParamSetForm())
            {
                paramSetForm.ShowDialog();
            }
        }

        private void pLCToolStripMenuItem_Click(object sender, EventArgs e)
        {
            string errorMsg = string.Empty;
            try
            {
                // 连接plc
                if (PlcControlToolStripMenuItem.Text.Equals("PLC连接"))
                {
                    exportLog("连接PLC");
                    if (plcCommunicationService.ConnectPlc(out errorMsg))
                    {
                        plcState = true;
                        exportLog("PLC已连接");
                        plcStatus.Text = "PLC已连接";
                        plcStatus.BackColor = Color.Lime;
                        PlcControlToolStripMenuItem.Text = "PLC断开";
                    }
                    else
                    {
                        exportLog("PLC连接失败："+errorMsg);
                    }
                }
                else if (PlcControlToolStripMenuItem.Text.Equals("PLC断开"))
                {
                    exportLog("断开PLC");
                    
                    if (plcCommunicationService.DisConnectPlc(out errorMsg))
                    {
                        plcState = false;
                        exportLog("PLC已断开");
                        plcStatus.Text = "PLC已断开";
                        plcStatus.BackColor = Color.Red;
                        PlcControlToolStripMenuItem.Text = "PLC连接";
                    }
                    else
                    {
                        exportLog("PLC断开连接失败："+errorMsg);
                    }
                }
            }catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }



        private void MainForm_Load(object sender, EventArgs e)
        {
            GlobalDelegate.updateUiLogDelegate("参数开始加载！");
            GlobalDelegate.updateUiLogDelegate("参数加载成功！");


            // 加载串口通信相关信息
            initailPortName();
            initailBaudRate();
            initailDataBits();
            initailParityBits();
            initailStopBits();

            // 初始化图表
            initialChart();
            // 初始化锁付数据统计
            initialDataGridView();
        }

        private void OpenButton_Click(object sender, EventArgs e)
        {
            try
            {
                if (OpenButton.Text.Equals("打开") && !serialPort.IsOpen)
                {
                    object item = SerialPortComboBox.SelectedItem;
                    if (null != item)
                    {
                        string portName = SerialPortComboBox.SelectedItem.ToString();
                        serialPort.PortName = portName;
                    }

                    serialPort.BaudRate = Convert.ToInt32(BaudComboBox.SelectedItem);
                    serialPort.DataBits = Convert.ToInt32(DatabitComboBox.SelectedItem);
                    Parity parity = (Parity)Enum.Parse(typeof(Parity), ParityComboBox.SelectedItem.ToString());
                    serialPort.Parity = parity;
                    StopBits stopBits = (StopBits)Enum.Parse(typeof(StopBits), StopComboBox.SelectedItem.ToString());
                    serialPort.StopBits = stopBits;
                    exportLog("连接螺丝机");
                    serialPort.Open();
                    exportLog("螺丝机已连接");
                    equipmentState = true;
                    OpenButton.Text = "关闭";
                    screwStatus.Text = "螺丝机已连接";
                    screwStatus.BackColor = Color.Lime;
                }
                else
                {
                    exportLog("断开螺丝机");
                    serialPort.Close();
                    exportLog("螺丝机已断开");
                    equipmentState = false;
                    OpenButton.Text = "打开";
                    screwStatus.Text = "螺丝机已断开";
                    screwStatus.BackColor = Color.Red;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void queryMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                using (DataQueryForm dataQueryForm = new DataQueryForm())
                {
                    dataQueryForm.ShowDialog();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void StartButton_Click(object sender, EventArgs e)
        {
            if (!plcState || !equipmentState)
            {
                MessageBox.Show("PLC未连接 或 螺丝机未连接");
            }
            else
            {
                if (StartTestButton.Text.Equals("开始测试"))
                {
                    autoTestService.startTest();
                    StartTestButton.Text = "停止测试";
                }
                else
                {
                    autoTestService.stopTest();
                    StartTestButton.Text = "开始测试";
                }
            }
        }


        #region 更新业务逻辑
        /// <summary>
        /// 更新UI日志
        /// </summary>
        /// <param name="msg"></param>
        private void updateUiLog(string msg)
        {
            // 需要切换到UI线程执行改方法
            this.Invoke(new Action(() =>
            {

                string[] lines = LogTxb.Lines;
                if (lines.Length > 200)
                {
                    LogTxb.Clear();
                }

                string logMsg = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + " " + msg + "\n";
                LogTxb.AppendText(logMsg);

            }));
        }

        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="bytes"></param>
        private void updateData(List<byte> bytes)
        {
            updateChart(bytes);
            updateDataGridView(bytes);
        }

        /// <summary>
        /// 更新图表曲线
        /// </summary>
        private void updateChart(List<byte> bytes)
        {
            List<double> xList = new List<double>();
            for (int i = 0; i < bytes.Count; i++)
            {
                xList.Add(i);
            }

            // 需要切换到UI线程执行改方法
            this.Invoke(new Action(() =>
            {
                TorqueChart.Series[0].Points.Clear();
                TorqueChart.Series[0].Points.DataBindXY(xList, bytes);
            }));
        }

        /// <summary>
        /// 更新锁付数据统计表格
        /// </summary>
        /// <param name="bytes"></param>
        private void updateDataGridView(List<byte> bytes)
        {
            // 最大扭力
            byte maxValue = bytes.Max();
            updateResultLabel(maxValue);
            // 存储最大扭力CSV文件
            DataStorageService csvDataStorageService = factory.getDataStorageService(DataStorageType.CSV);
            csvDataStorageService.SaveMaxTorqueData(maxValue, out errorMsg);
            // 存储最大扭力到数据库中
            DataStorageService mysqlDataStorageService = factory.getDataStorageService(DataStorageType.MYSQL);
            mysqlDataStorageService.SaveMaxTorqueData(maxValue, out errorMsg);
            // 平均扭力
            double averageValue = bytes.Select(item => Convert.ToInt32(item)).ToList().Average();
            this.Invoke(new Action(() =>
            {
                int index = DataGridView.Rows.Add();
                DataGridView.Rows[index].Cells[0].Value = index;
                DataGridView.Rows[index].Cells[1].Value = maxValue;
                DataGridView.Rows[index].Cells[2].Value = averageValue;
                DataGridView.Rows[index].Cells[3].Value = DateTime.Now.ToString();
            }));
        }

        /// <summary>
        /// 更新锁付结果图
        /// </summary>
        private void updateResultLabel(double maxTorque)
        {
            this.Invoke(new Action(() =>
            {
                if (maxTorque >= GlobalParam.getInstance().param.screwLimit)
                {
                    ResultLabel.Text = "OK";
                    ResultLabel.BackColor = Color.LimeGreen;
                }
                else
                {
                    ResultLabel.Text = "NG";
                    ResultLabel.BackColor = Color.Red;
                }
            }));
        }
        #endregion


        #region 初始化串口通信数据
        /// <summary>
        /// 加载串口号
        /// </summary>
        private void initailPortName()
        {
            string[] ports = SerialPort.GetPortNames();
            SerialPortComboBox.Items.Clear();
            if(null != ports && ports.Length > 0)
            {
                SerialPortComboBox.Items.AddRange(ports);
                SerialPortComboBox.SelectedIndex = 0;
            }
            else
            {
                MessageBox.Show("设备的串口号识别错误！");
            }
            
        }

        /// <summary>
        /// 加载波特率
        /// </summary>
        private void initailBaudRate()
        {
            int[] baudRate = new int[] { 4800, 9600, 115200 };
            BaudComboBox.Items.Clear();
            BaudComboBox.Items.AddRange(baudRate.Select(item => item.ToString()).ToArray());
            BaudComboBox.SelectedIndex = 1;
        }

        /// <summary>
        /// 加载数据位
        /// </summary>
        private void initailDataBits()
        {
            int[] databits = new int[] { 6, 7, 8 };
            DatabitComboBox.Items.Clear();
            DatabitComboBox.Items.AddRange(databits.Select(item => item.ToString()).ToArray());
            DatabitComboBox.SelectedIndex = 2;
        }

        /// <summary>
        /// 加载校验位
        /// </summary>
        private void initailParityBits()
        {
            string[] paritys = new string[] { Parity.None.ToString(),Parity.Odd.ToString(), Parity.Even.ToString(),
                Parity.Mark.ToString(),Parity.Space.ToString()};
            ParityComboBox.Items.Clear();
            ParityComboBox.Items.AddRange(paritys);
            ParityComboBox.SelectedIndex = 0;
        }

        /// <summary>
        /// 加载停止位
        /// </summary>
        private void initailStopBits()
        {
            double[] stopBits = new double[] {1,1.5,2};
            StopComboBox.Items.Clear();
            StopComboBox.Items.AddRange(stopBits.Select(item => item.ToString()).ToArray());
            StopComboBox.SelectedIndex = 0;
        }

        #endregion

        #region 初始化UI
        /// <summary>
        /// 初始化扭力监控图表
        /// </summary>
        private void initialChart()
        {
            TorqueChart.Series[0].ChartType = SeriesChartType.Line;
            TorqueChart.Series[0].Color = Color.Red;
            TorqueChart.Series[0].LegendText = "扭力";
        }

        /// <summary>
        /// 初始化锁付数据统计表格
        /// </summary>
        private void initialDataGridView()
        {
            // 清除默认数据
            DataGridView.Rows.Clear();
            DataGridView.Columns.Clear();

            // 添加列
            DataGridView.Columns.Add("序号", "序号");
            DataGridView.Columns.Add("最大扭力", "最大扭力");
            DataGridView.Columns.Add("平均扭力", "平均扭力");
            DataGridView.Columns.Add("测试时间", "测试时间");
            DataGridView.RowHeadersVisible = false;
        }
        #endregion

        /// <summary>
        /// 输出日志
        /// </summary>
        /// <param name="message"></param>
        private void exportLog(string message)
        {
            GlobalDelegate.updateUiLogDelegate(message);
            logService.WriteLog(message);
        }
    }

}
